package com.mbigger.netty.ch6;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.codec.FixedLengthFrameDecoder;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.LineBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GenericFutureListener;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class NettyServer {

    /**
     * 在端口绑定失败之后，重新调用自身方法，并且把端口号加一
     * 
     * @param serverBootstrap
     *            TCP Server 启动辅助类
     * @param port
     *            需要绑定的端口号
     */

    private static void bind(final ServerBootstrap serverBootstrap, final int port) {
        serverBootstrap.bind(port).addListener(new GenericFutureListener<Future<? super Void>>() {
            public void operationComplete(Future<? super Void> future) {
                ChannelFuture channelFuture = (ChannelFuture) future;
                Channel channel = channelFuture.channel();
                if (future.isSuccess()) {
                    log.info("绑定成功, 本地地址[{}]", channel.localAddress());
                } else {
                    log.error("端口[{}]绑定失败, 失败原因: {}", port, future.cause().getMessage());
                    bind(serverBootstrap, port + 1);
                }
            }
        });
    }

    public static void main(String[] args) {

        int RUN_MODE = 1;

        int port = 49664;

        NioEventLoopGroup bossGroup = new NioEventLoopGroup();
        NioEventLoopGroup workerGroup = new NioEventLoopGroup();

        ServerBootstrap serverBootstrap = new ServerBootstrap();
        serverBootstrap.handler(new ChannelInitializer<NioServerSocketChannel>() {
            protected void initChannel(NioServerSocketChannel ch) {
                log.info("服务端启动中...");
            }
        });
        serverBootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)
                .childHandler(new ChannelInitializer<NioSocketChannel>() {
                    protected void initChannel(NioSocketChannel ch) {

                        log.info("init channel !");

                        if (RUN_MODE == 1) {
                            // FixedLengthFrameDecoder
                            // hello server,im a client
                            ch.pipeline().addLast(new FixedLengthFrameDecoder(24));
                            ch.pipeline().addLast(new StringDecoder());
                            ch.pipeline().addLast(new NettyServerHandler());
                        } else if (RUN_MODE == 2) {
                            // LineBasedFrameDecoder
                            ch.pipeline().addLast(new LineBasedFrameDecoder(1024));
                            ch.pipeline().addLast(new StringDecoder());
                            ch.pipeline().addLast(new NettyServerHandler());
                        } else if (RUN_MODE == 3) {
                            // DelimiterBasedFrameDecoder
                            ByteBuf delimiter = Unpooled.copiedBuffer(new byte[] { (byte) 0xEB, (byte) 0x90,
                                    (byte) 0xEB, (byte) 0x90, (byte) 0xEB, (byte) 0x90 });
                            ch.pipeline().addLast(new DelimiterBasedFrameDecoder(2048, delimiter));
                            ch.pipeline().addLast(new NettyServerBytebufHandler());
                        } else if (RUN_MODE == 4) {
                            // LengthFieldBasedFrameDecoder
                            ch.pipeline().addLast(new LengthFieldBasedFrameDecoder(255, 1, 1, 0, 0, true));
                            ch.pipeline().addLast(new NettyServerBytebufHandler());
                        } else if (RUN_MODE == 5) {
                            // LengthFieldBasedFrameDecoder
                            ch.pipeline().addLast(new FrameReplayingDecoder());
                            ch.pipeline().addLast(new NettyServerBytebufHandler());
                        }

                    }
                });

        bind(serverBootstrap, port);

    }
}
